home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Sample Code / Games / MoofWars / Tim's Libraries / TGraphicCollection.cp < prev    next >
Encoding:
Text File  |  1996-08-19  |  18.9 KB  |  639 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #    TGraphicCollection.cp
  4. #    
  5. #
  6. #    The TGraphicCollection class is a group of related TGraphic objects.  Essentially,
  7. #   the API for this class mimics the TGraphic class very closely, except that all of
  8. #   the routines in TGraphicCollection pass in an index to which TGraphic object is being
  9. #   referred to.
  10. #
  11. #    Because this class relies so heavily on TGraphic, we share all of TGraphic's
  12. #    limitations.  In fact, any of the routines used to prepare drawing in TGraphic are
  13. #    used without modification, since they apply to ALL TGraphic objects, regardless of
  14. #    if they are in a collection or not.
  15. #
  16. #    Note that this class isn't currently intended to be subclassed, so all of the methods
  17. #    are non-virtual.  This might change if at some point we determine we need to create
  18. #    a subclass.#
  19. #
  20. #    Author: Timothy Carroll
  21. #    Apple Developer Technical Support
  22. #    timc@apple.com
  23. #
  24. #    Modification History: 
  25. #
  26. #    6/1/96        TMC     Initial Release
  27. #
  28. #    Copyright © 1996 Apple Computer, Inc., All Rights Reserved
  29. #
  30. #
  31. #    You may incorporate this sample code into your applications without
  32. #    restriction, though the sample code has been provided "AS IS" and the
  33. #    responsibility for its operation is 100% yours.  However, what you are
  34. #    not permitted to do is to redistribute the source as "DSC Sample Code"
  35. #    after having made changes. If you're going to re-distribute the source,
  36. #    we require that you make it clear in the source that the code was
  37. #    descended from Apple Sample Code, but that you've made changes.
  38. #
  39. *************************************************************************************/
  40.  
  41. #include <Memory.h>
  42. #include <Resources.h>
  43.  
  44. #include "TGraphicCollection.h"
  45.  
  46. /****************************************************************************************************
  47.  
  48.     Internal Declarations
  49.     
  50.     We will hold the list of created TGraphicCollectionObjects in a handle.  This handle is 
  51.     automatically created the first time we load a TGraphicCollection and is deallocated when
  52.     the list is empty.
  53.     
  54.      All of the allocation and deallocation is handled by the static NewCollection call.
  55.     
  56.     NewCollection has a few utility routines it calls on to manage the handle.  Mainly they do
  57.     the searching, insertion and deletion from the list.
  58. ****************************************************************************************************/
  59.  
  60. static Handle gGraphicCollectionList = NULL;
  61. static unsigned long gNumberItemsInList = 0;
  62.  
  63.  
  64.  
  65. static OSErr InsertCollectionIntoList (TGraphicCollection *theCollection, UInt32 index);
  66. static OSErr DeleteCollectionFromList (UInt32 index);
  67. static OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index);
  68.  
  69. /****************************************************************************************************
  70.     InsertCollectionIntoList
  71.     
  72.     This routine creates the handle if necessary, and otherwise inserts the TGraphicCollection
  73.     into the list at the index location given.
  74.     
  75.     Assumptions:
  76.         theCollection must be a legitimate TGraphicCollection -- no NULL parameters.
  77.         index must be no more than 1 larger than gNumberItemsInList. ?????
  78. ****************************************************************************************************/
  79.  
  80. OSErr InsertCollectionIntoList (TGraphicCollection *theCollection, UInt32 index)
  81. {
  82.     OSErr theErr = noErr;
  83.  
  84. #if qDebugging
  85.     if (index > gNumberItemsInList)
  86.         SIGNAL_ERROR ("\pAttempting to insert collection at invalid index")
  87.     if (theCollection == NULL)
  88.         SIGNAL_ERROR ("\pAttempting to insert a null collection into the list")    
  89.     
  90. #endif
  91.     
  92.     if (gGraphicCollectionList == NULL)
  93.     {
  94.         gNumberItemsInList = 1;
  95.         
  96.         gGraphicCollectionList = NewHandleClear (sizeof (TGraphicCollection *));
  97.         theErr = MemError();
  98.         
  99.         FAIL_OSERR (theErr, "\pCouldn't allocate a new handle of information")
  100.         FAIL_NIL (gGraphicCollectionList, "\pCouldn't allocate a new handle of information")
  101.         
  102.     }
  103.     else
  104.     {
  105.         gNumberItemsInList++;
  106.         SetHandleSize(gGraphicCollectionList,gNumberItemsInList*sizeof(TGraphicCollection *));
  107.         
  108.         theErr = MemError();
  109.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  110.         FAIL_NIL (gGraphicCollectionList, "\pCouldn't resize the list handle")
  111.         
  112.         // Shift the data to make room
  113.         BlockMoveData(    (*(TGraphicCollection ***)gGraphicCollectionList)+index,
  114.                         (*(TGraphicCollection ***)gGraphicCollectionList)+index+1,
  115.                         (gNumberItemsInList - index-1) * sizeof(TGraphicCollection *));
  116.     }
  117.     
  118.     // finally, set the new object in place
  119.             *((*(TGraphicCollection ***) gGraphicCollectionList)+index)     = theCollection;
  120.  
  121.     return noErr;
  122.     
  123.     error:
  124.     
  125.     
  126.     if (theErr == noErr)
  127.         theErr = paramErr;
  128.     return theErr;
  129. }
  130.  
  131.  
  132. /****************************************************************************************************
  133.     DeleteCollectionFromList
  134.     
  135.     This routine removes the collection from the list and destroys it.  If there are no more items
  136.     in the list then we dispose of the handle.
  137.     
  138.     Assumptions:
  139.     index must be within the list.
  140. ****************************************************************************************************/
  141. OSErr DeleteCollectionFromList (UInt32 index)
  142. {
  143.     OSErr theErr;
  144.     
  145.     gNumberItemsInList--;
  146.     
  147.     //    slide remaining elements up
  148.     
  149.     BlockMoveData(    (*(TGraphicCollection ***)gGraphicCollectionList)+index+1,
  150.                     (*(TGraphicCollection ***)gGraphicCollectionList)+index,
  151.                     (gNumberItemsInList - index) * sizeof(TGraphicCollection *));
  152.  
  153.     //    cut back the storage and dispose of the handle if we have no items left
  154.     
  155.     
  156.     if (gNumberItemsInList> 0)
  157.     {
  158.         SetHandleSize((Handle) gGraphicCollectionList,gNumberItemsInList*sizeof(TGraphicCollection *));
  159.         theErr = MemError();
  160.         FAIL_OSERR (theErr, "\pCouldn't resize the list handle")
  161.         FAIL_NIL (gGraphicCollectionList, "\pCouldn't resize the list handle")
  162.     }
  163.     
  164.     else
  165.     {
  166.         DisposeHandle (gGraphicCollectionList);
  167.         gGraphicCollectionList = NULL;
  168.     }
  169.     
  170.     
  171.     return noErr;
  172.     error:
  173.     
  174.     
  175.     if (theErr == noErr)
  176.         theErr = paramErr;
  177.     return theErr;
  178. }
  179.  
  180.  
  181. /****************************************************************************************************
  182.     SearchCollectionList
  183.     
  184.     This routine searches through the list and attempts to find an existing TGraphicCollection with
  185.     that resID.  If it finds one with that resID, then it returns the index to that collection and
  186.     sets found to true.  If it doesn't find that resource, then it sets found to false AND sets the
  187.     index to where it should be inserted into the list.
  188. ****************************************************************************************************/
  189. OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index)
  190. {    
  191.     UInt32 low = 0;
  192.     UInt32 high = gNumberItemsInList;
  193.     UInt32 tempIndex;
  194.     TGraphicCollection *theItem;
  195.     
  196.     OSErr theErr = noErr;
  197.     
  198.     *found = false;
  199.     
  200.     while (low < high)
  201.         {
  202.         tempIndex = (low+high) >> 1;
  203.         
  204.         theItem = (*(TGraphicCollection ***)gGraphicCollectionList)[tempIndex];
  205.         
  206.         FAIL_NIL (theItem, "\pBad TGraphic object")
  207.         
  208.         if (resID < theItem->GetResID())
  209.             high = tempIndex;                    //    element is below "high"
  210.         else if (resID == theItem->GetResID())
  211.             {
  212.             *found = true;
  213.             *index = tempIndex;
  214.             return noErr;
  215.             }
  216.         else
  217.             low = tempIndex+1;                    //    element is above "low"
  218.         }
  219.     
  220.     // use final calculations to put insert in the right place in the list
  221.     *index = (low+high) >> 1;
  222.     return noErr;
  223.     
  224.     error:
  225.     
  226.     if (theErr == noErr)
  227.         theErr = paramErr;
  228.     return theErr;
  229.  
  230.  
  231. }
  232. /****************************************************************************************************
  233.     TGraphicCollection::NewCollection
  234.     
  235.     This routine merely uses the routines we created above to properly create and load
  236.     the TGraphicCollections.
  237. ****************************************************************************************************/
  238. TGraphicCollection
  239. *TGraphicCollection::NewCollection (SInt16 resID)
  240. {
  241.     unsigned long        listIndex;
  242.     Boolean             tableAlreadyExists;
  243.     TGraphicCollection    *newCollection = NULL;
  244.     OSErr                theErr;
  245.     
  246.     theErr = SearchCollectionList (resID, &tableAlreadyExists, &listIndex);
  247.     FAIL_OSERR(theErr,"\pCouldn't search the collection list in TGraphicCollection::NewCollection")
  248.     
  249.     if (tableAlreadyExists)
  250.     {
  251.         // find the existing collection and add 1 to the ref count.
  252.         newCollection = (*(TGraphicCollection ***)gGraphicCollectionList)[listIndex];
  253.         newCollection->AddReference();
  254.     }
  255.     else
  256.     {
  257.         // create a new collection
  258.         newCollection = new TGraphicCollection(resID);
  259.         theErr = newCollection->CreateCollection ();
  260.         FAIL_OSERR(theErr,"\pCouldn't create new TGraphicCollection")
  261.         theErr = InsertCollectionIntoList(newCollection, listIndex);
  262.         FAIL_OSERR(theErr, "\pCouldn't add new TGraphicCollection to list")
  263.         newCollection->AddReference();
  264.     }
  265.     
  266.     return newCollection;
  267.     error:
  268.         if (newCollection != NULL)
  269.             delete newCollection;
  270.         return NULL;
  271. }
  272.  
  273.  
  274. /****************************************************************************************************
  275.     TGraphicCollection::AddReference
  276. ****************************************************************************************************/
  277.  
  278. void
  279. TGraphicCollection::AddReference (void)
  280.    {
  281.        fReferenceCount++;
  282.    }
  283.    
  284.    
  285. /****************************************************************************************************
  286.     TGraphicCollection::DisposeReference
  287. ****************************************************************************************************/
  288.  
  289. void 
  290. TGraphicCollection::DisposeReference (void)
  291. {
  292.        fReferenceCount--;
  293.        if (fReferenceCount == 0)
  294.        {
  295.            UInt32                listIndex;
  296.         Boolean             tableEntry;
  297.         OSErr                theErr;
  298.  
  299.         theErr = SearchCollectionList (fResID, &tableEntry, &listIndex);
  300.                 
  301.         FAIL_OSERR (theErr, "\pFailed to search the CollectionList")
  302.         FAIL_FALSE (tableEntry, "\pFailed to find an existing TGraphicCollection in list")
  303.                 
  304.         theErr = DeleteCollectionFromList(listIndex);
  305.         FAIL_OSERR (theErr, "\pFailed to delete Collection from the list")
  306.                 
  307.            delete this;
  308.        }
  309.            
  310.     error:
  311.        return;
  312. }
  313.    
  314.  
  315. /****************************************************************************************************
  316.     TGraphicCollection::TGraphicCollection
  317.     
  318.     The constructor.  We just set the variables to some nice, clean values and return.  The real
  319.     work will be done in CreateCollection, which actually can return an OSERR
  320. ****************************************************************************************************/
  321.  
  322. TGraphicCollection::TGraphicCollection (SInt16 resID)
  323. {
  324.     fResID = resID;
  325.     fReferenceCount = 0;
  326.     fGraphics = NULL;
  327. }
  328.  
  329.  
  330. /****************************************************************************************************
  331.     TGraphicCollection::~TGraphicCollection
  332.     
  333.     The destructor, which pushes all the work of destroying the data to a separate routine which
  334.     also can return an OSErr.
  335. ****************************************************************************************************/
  336.  
  337. TGraphicCollection::~TGraphicCollection (void)
  338. {
  339.     if (fGraphics != NULL)
  340.         {
  341.         OSErr theErr = DestroyCollection();
  342.         FAIL_OSERR (theErr, "\pFailed to destroy the TGraphicCollection data")
  343.         }
  344.         
  345.     error:
  346.     return;
  347. }
  348.  
  349.  
  350. /****************************************************************************************************
  351.     TGraphicCollection::CreateCollection
  352.     
  353.     This routine uses the resource number we passed into the contructor to load the TGraphicCollection
  354.     from the 'SptA' resource we created for it.  Note that we don't make any assumptions about
  355.     the resource file being used, so the correct resource file already needs to be opened for this
  356.     call to work.
  357. ****************************************************************************************************/
  358.  
  359. OSErr TGraphicCollection::CreateCollection(void)
  360. {
  361.     // Load the resource with our graphic collection's data.  The format of this resource is basically
  362.     // a 2 byte unsigned integer for the number of elements in the list, followed by the resource
  363.     // ID for each of the TGraphic objects.
  364.  
  365.     UInt16 numGraphics;
  366.     Handle collectionResource = Get1Resource ('SptA', fResID);
  367.     OSErr theErr = ResError();
  368.     
  369.     FAIL_OSERR (theErr, "\pResource manager couldn't load the sprite resource")
  370.     FAIL_NIL (collectionResource, "\pResource manager returned a null handle")
  371.     
  372.     // First things, find out the number of objects in the graphic. Then allocate
  373.     // a handle to hold the TGraphic pointers.
  374.  
  375.     numGraphics = *((SInt16 *) (*collectionResource));
  376.     
  377.     // Later, we can change the format perhaps, and pass in a UInt32 so that we
  378.     // don't have to convert it here.  Saves an assembly instruction
  379.     
  380.     fNumberOfGraphics = numGraphics;
  381.     
  382.     fGraphics = NewHandleClear (fNumberOfGraphics * sizeof (TGraphic *));
  383.     
  384.     FAIL_NIL (fGraphics, "\pCouldn't allocate handle to hold the TGraphic objects")
  385.     
  386.     // Now we'll load each Graphic, one at a time, and add them to the handle, reporting
  387.     // an error if any of them fail to load.
  388.     UInt32 loop;
  389.     
  390.     HLock (fGraphics);
  391.     
  392.     for (loop = 0; loop < fNumberOfGraphics; loop++)
  393.     {
  394.         SInt16 graphicResID = *((SInt16 *)
  395.                                 ((*collectionResource)+sizeof (UInt16)+sizeof (SInt16)*loop));
  396.     // We've loaded the list of objects and their data.  This list consists of a
  397.     // 2 byte value (the number of graphics) followed by 2 byte values for each
  398.     // graphic's resID. We'll load and enter them into the table in
  399.     // order.
  400.     
  401.         TGraphic *theGraphic = TGraphic::NewGraphic (graphicResID);
  402.         FAIL_NIL (theGraphic, "\pFailed to load graphic for collection")
  403.         
  404.         *((*(TGraphic ***)fGraphics)+loop)     = theGraphic;
  405.     }
  406.  
  407.     HUnlock (fGraphics);
  408.     ReleaseResource (collectionResource);
  409.     
  410.     goto cleanup;
  411.     
  412.     error:
  413.     if (theErr == noErr)
  414.         theErr = paramErr;
  415.     
  416.     cleanup:
  417.     // Note that we don't explictly call DestroyCollection here, since it will be called
  418.     // when the object is destroyed, which should happen whenever we don't report noErr.
  419.     if (collectionResource != NULL)
  420.         ReleaseResource (collectionResource);
  421.     
  422.     // set a generic error code for those cases we don't have a real error code
  423.         
  424.  
  425.     return theErr;
  426. }
  427.  
  428.  
  429. /****************************************************************************************************
  430.     TGraphicCollection::DestroyCollection
  431.     
  432.     Throw away all of the objects that we're created.  We do check for null TGraphic objects here,
  433.     and properly skip null objects that might not have been finished from the create calls.
  434. ****************************************************************************************************/
  435.  
  436. OSErr
  437. TGraphicCollection::DestroyCollection (void)
  438. {
  439.     UInt32 loop;
  440.     
  441.     HLock (fGraphics);
  442.     for (loop = 0; loop < fNumberOfGraphics ; loop++)
  443.     {        
  444.         TGraphic *theGraphic = *((*(TGraphic ***)fGraphics)+loop);
  445.         if (theGraphic != NULL)
  446.             theGraphic->DisposeReference();
  447.     }
  448.     DisposeHandle (fGraphics);
  449.     fGraphics = NULL;
  450.     
  451.     return noErr;
  452. }
  453.  
  454.  
  455.  
  456.  
  457.  
  458. /****************************************************************************************************
  459.     TGraphicCollection::LockCollection
  460.  
  461. ****************************************************************************************************/
  462.  
  463. OSErr
  464. TGraphicCollection::LockCollection (void)
  465. {
  466.     UInt32 loop;
  467.     OSErr theErr = noErr;
  468.     
  469.     MoveHHi (fGraphics);
  470.     theErr = MemError();
  471.     FAIL_OSERR (theErr, "\pCouldn't move fGraphics handle high")
  472.     HLock (fGraphics);
  473.     theErr = MemError();
  474.     FAIL_OSERR (theErr, "\pCouldn't lock fGraphics handle")
  475.     
  476.     TGraphic **ptrToGraphics = (TGraphic **) *fGraphics;
  477.     
  478.     for (loop = 0; loop < fNumberOfGraphics ; loop++)
  479.     {
  480.         TGraphic *theGraphic = *ptrToGraphics++;
  481.         theGraphic->LockGraphic();
  482.     }
  483.     
  484.     return noErr;
  485.     
  486.     error:
  487.     return theErr;
  488. }
  489.  
  490.  
  491. /****************************************************************************************************
  492.     TGraphicCollection::LockCollection
  493.  
  494. ****************************************************************************************************/
  495.  
  496. OSErr
  497. TGraphicCollection::UnlockCollection (void)
  498. {
  499.     UInt32 loop;
  500.     OSErr theErr = noErr;
  501.     
  502.     // Should still be locked from the lock collection call.  We should do some testing
  503.     // to make sure we aren't locking and unlocking things multiple times here.
  504.     TGraphic **ptrToGraphics = (TGraphic **) *fGraphics;
  505.     
  506.     for (loop = 0; loop < fNumberOfGraphics ; loop++)
  507.     {
  508.         TGraphic *theGraphic = *ptrToGraphics++;
  509.         theGraphic->UnlockGraphic();
  510.     }
  511.     
  512.     HUnlock (fGraphics);
  513.     theErr = MemError();
  514.     FAIL_OSERR (theErr, "\pCouldn't unlock fGraphics handle")
  515.     
  516.     return noErr;
  517.     
  518.     error:
  519.     return theErr;
  520. }
  521.  
  522.  
  523. /****************************************************************************************************
  524.     TGraphicCollection::GetBounds
  525.  
  526. ****************************************************************************************************/
  527.  
  528. Rect
  529. TGraphicCollection::GetBounds (UInt32 index)
  530. {
  531.     TGraphic *theGraphic;
  532. #if qDebugging
  533.     if  (index >= fNumberOfGraphics)
  534.         // We're outside of the bounds of the graphics table here.  Debugger time! :-)
  535.             SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
  536. #endif
  537.  
  538.     theGraphic = *((*(TGraphic ***)fGraphics)+index);
  539.  
  540. #if qDebugging
  541.     if (theGraphic == NULL)
  542.             SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
  543. #endif
  544.     
  545.     return (theGraphic->GetBounds ());
  546.  
  547. #if qDebugging
  548.     error:
  549.     Rect theRect = {0,0,0,0};
  550.     return theRect;
  551. #endif
  552. }
  553.  
  554.  
  555. /****************************************************************************************************
  556.     TGraphicCollection::CopyImage
  557.  
  558. ****************************************************************************************************/
  559.  
  560. void
  561. TGraphicCollection::CopyImage (UInt32 index, SInt32 top, SInt32 left, Boolean useBackground)
  562. {
  563.     TGraphic *theGraphic;
  564. #if qDebugging
  565.     if  (index >= fNumberOfGraphics)
  566.         // We're outside of the bounds of the graphics table here.  Debugger time! :-)
  567.             SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
  568. #endif
  569.  
  570.     theGraphic = *((*(TGraphic ***)fGraphics)+index);
  571.  
  572. #if qDebugging
  573.     if (theGraphic == NULL)
  574.             SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
  575. #endif
  576.     
  577.     theGraphic->CopyImage(top, left, useBackground);
  578.  
  579.     error:
  580.     return;
  581. }
  582.  
  583.  
  584. /****************************************************************************************************
  585.     TGraphicCollection::HitTest
  586.  
  587. ****************************************************************************************************/
  588.  
  589. Boolean
  590. TGraphicCollection::HitTest (UInt32 index, SInt32 v, SInt32 h)
  591. {
  592.     TGraphic *theGraphic;
  593. #if qDebugging
  594.     if  (index >= fNumberOfGraphics)
  595.         // We're outside of the bounds of the graphics table here.  Debugger time! :-)
  596.             SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
  597. #endif
  598.  
  599.     theGraphic = *((*(TGraphic ***)fGraphics)+index);
  600.  
  601. #if qDebugging
  602.     if (theGraphic == NULL)
  603.             SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
  604. #endif
  605.     
  606.     return theGraphic->HitTest (v, h);
  607.  
  608.     error:
  609.     return false;
  610. }
  611.  
  612.  
  613. /****************************************************************************************************
  614.     TGraphicCollection::GetGraphicObject
  615.  
  616. ****************************************************************************************************/
  617.  
  618. TGraphic 
  619. *TGraphicCollection::GetTGraphic (UInt32 index)
  620. {
  621.     TGraphic *theGraphic;
  622. #if qDebugging
  623.     if  (index >= fNumberOfGraphics)
  624.         // We're outside of the bounds of the graphics table here.  Debugger time! :-)
  625.             SIGNAL_ERROR("\ptried to index a TGraphic that was out of bounds");
  626. #endif
  627.  
  628.     theGraphic = *((*(TGraphic ***)fGraphics)+index);
  629. #if qDebugging
  630.     if (theGraphic == NULL)
  631.             SIGNAL_ERROR("\pRetrieved a null TGRAPHIC object")
  632. #endif
  633.     
  634.     return theGraphic;
  635.  
  636.     error:
  637.     
  638.     return NULL;
  639. }